package com.xxl.job.common.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.springframework.cglib.beans.BeanMap;

import javax.servlet.http.HttpServletRequest;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 公共方法封装类
 *
 * @version : 1.0
 * @author  : zyc
 * @date    : 2023/8/30 15:12
 */
public class CommonUitl {


    /**
     * 前置补位
     *
     * @param str    需要补位的字符串
     * @param fill   补位的字符串
     * @param length 部位后字符串的长度
     * @return
     */
    public static String fillStringBeforeString(String str, String fill, int length) {
        if (str.length() < length) {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < length - str.length(); i++) {
                sb.append(fill);
            }
            sb.append(str);
            return sb.toString();
        } else {
            return str;
        }
    }

    /**
     * 后置补位
     *
     * @param str    需要补位的字符串
     * @param fill   补位的字符串
     * @param length 部位后字符串的长度
     * @return
     */
    public static String fillStringAfterString(String str, String fill, int length) {
        if (str.length() < length) {
            StringBuilder sb = new StringBuilder();
            sb.append(str);
            for (int i = 0; i < length - str.length(); i++) {
                sb.append(fill);
            }
            return sb.toString();
        } else {
            return str;
        }
    }

    public static String getQrcodeRandom(int len) {
        int digit = (int) Math.pow(10, len - 1);
        int rs = new Random().nextInt(digit * 10);
        if (rs < digit) {
            rs += digit;
        }
        return String.valueOf(rs);
    }

    public static Map<String, Object> checkParamesBody(HttpServletRequest request) {
        Map<String, Object> params = new HashMap<String, Object>();
        BufferedReader br;
        try {
            br = request.getReader();
            String str, wholeStr = "";
            while ((str = br.readLine()) != null) {
                wholeStr += str;
            }
            if (StringUtils.isNotEmpty(wholeStr)) {
                params = JSON.parseObject(wholeStr, Map.class);
            }
        } catch (IOException e1) {
            e1.printStackTrace();
        }
        return params;
    }

    /**
     * 将前端返回的参数存放到Map对象中
     *
     * @param request
     * @return
     */
    public static Map<String, Object> checkParames(HttpServletRequest request) {
        Map<String, Object> map = null;
        Map paramesMap = null;
        String name = null;
        String[] values = null;
        try {
            map = new HashMap<String, Object>();
            paramesMap = request.getParameterMap();
            if (paramesMap != null) {
                for (Iterator iter = paramesMap.keySet().iterator(); iter.hasNext(); ) {
                    name = (String) iter.next();
                    values = (String[]) paramesMap.get(name);
                    map.put(name, values[0]);
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return map;
    }


    /**
     * public int indexOf(int ch, int fromIndex)
     * 返回在此字符串中第一次出现指定字符处的索引，从指定的索引开始搜索
     *
     * @param srcText
     * @param findText
     * @return
     */
    public static int appearNumber(String srcText, String findText) {
        int count = 0;
        int index = 0;
        while ((index = srcText.indexOf(findText, index)) != -1) {
            index = index + findText.length();
            count++;
        }
        return count;
    }

    /**
     *      * map 转实体类
     *      * @param clazz
     *      * @param map
     *      * @param <T>
     *      * @return
     *      
     */
    public static <T> T convertMapToBean(Class<T> clazz, Map<String, Object> map) {
        T obj = null;
        try {
            BeanInfo beanInfo = Introspector.getBeanInfo(clazz);
            obj = clazz.newInstance(); // 创建 JavaBean 对象
            // 给 JavaBean 对象的属性赋值
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            for (int i = 0; i < propertyDescriptors.length; i++) {
                PropertyDescriptor descriptor = propertyDescriptors[i];
                String propertyName = descriptor.getName();
                if (map.containsKey(propertyName)) {
                    // 下面一句可以 try 起来，这样当一个属性赋值失败的时候就不会影响其他属性赋值。
                    Object value = map.get(propertyName);
                    if ("".equals(value)) {
                        value = null;
                    }
                    Object[] args = new Object[1];
                    args[0] = value;
                    descriptor.getWriteMethod().invoke(obj, args);
                }
            }
        } catch (IllegalAccessException e) {
        } catch (IntrospectionException e) {
        } catch (IllegalArgumentException e) {
        } catch (InstantiationException e) {
        } catch (InvocationTargetException e) {
        } catch (Exception e) {
        }
        return (T) obj;
    }

    /**
     * 返回某个字符串中某特殊字符第lin次出现的位置
     *
     * @param str 目标字符串
     * @param ch  特殊字符串
     * @param lin 第几次
     * @return
     */
    public static int lastIndexLetter(String str, char ch, int lin) {
        char[] array = str.toCharArray();
        for (int i = 0; i < array.length; ++i) {
            if (array[i] == ch && --lin == 0) {
                return i;
            }
        }
        return -1;
    }

    /**
     * 将对象属性转化为map结合
     */
    public static <T> Map<String, Object> beanToMap(T bean) {
        Map<String, Object> map = new HashMap<>();
        if (bean != null) {
            BeanMap beanMap = BeanMap.create(bean);
            for (Object key : beanMap.keySet()) {
                map.put(key + "", beanMap.get(key));
            }
        }
        return map;
    }

    /**
     * 将map集合中的数据转化为指定对象的同名属性中
     */
    public static <T> T mapToBean(Map<String, Object> map, Class<T> clazz) throws Exception {
        T bean = clazz.newInstance();
        BeanMap beanMap = BeanMap.create(bean);
        beanMap.putAll(map);
        return bean;
    }

    /**
     * 将一个以逗号分隔的字符串转化成数组  再封装成list集合
     *
     * @param str
     * @return list
     */
    public static List<Object> ArrayStrToList(String str) {
        List<Object> list = new ArrayList<Object>();
        String[] arraystr = str.split(",");
        for (int i = 0; i < arraystr.length; i++) {
            list.add(arraystr[i]);
            System.out.println(arraystr[i]);
        }
        return list;
    }

    /**
     * Object类型转List
     *
     * @author: zyc
     * @return:
     * @date: 2022/6/11
     */
    public static <T> List<T> castList(Object obj, Class<T> clazz) {
        List<T> result = new ArrayList<T>();
        if (obj instanceof List<?>) {
            for (Object o : (List<?>) obj) {
                result.add(clazz.cast(o));
            }
            return result;
        }
        return null;
    }


    public static Map<String, Object> getObjectToMap(Object obj) throws IllegalAccessException {
        Map<String, Object> map = new LinkedHashMap<String, Object>();
        Class<?> clazz = obj.getClass();
        System.out.println(clazz);
        for (Field field : clazz.getDeclaredFields()) {
            field.setAccessible(true);
            String fieldName = field.getName();
            Object value = field.get(obj);
            if (value == null) {
                value = "";
            }
            map.put(fieldName, value);
        }
        return map;
    }

    /**
     * json字符串转对象
     *
     * @param pojo
     * @param tclass
     * @param <T>
     * @return
     */
    public static <T> T JsonToObject(String pojo, Class<T> tclass) {
        try {
            return com.alibaba.fastjson.JSONObject.parseObject(pojo, tclass);
        } catch (Exception e) {
            System.out.println(tclass + "转 JSON 失败");
        }
        return null;
    }

    /**
     * json 转 List<T>
     */
    public static <T> List<T> jsonToList(String jsonString, Class<T> clazz) {
        @SuppressWarnings("unchecked")
        List<T> ts = (List<T>) com.alibaba.fastjson.JSONArray.parseArray(jsonString, clazz);
        return ts;
    }

    public static boolean isHave(String[] strs, String s) {

        /*此方法有两个参数，第一个是要查找的字符串数组，第二个是要查找的字符或字符串*/
        int i = strs.length;
        while (i-- > 0) {
            if (strs[i].equals(s)) {
                return true;
            }
        }
        return false;
    }

    /*
     * 1.一个运用基本类的实例
     * MessageDigest 对象开始被初始化。该对象通过使用 update 方法处理数据。
     * 任何时候都可以调用 reset 方法重置摘要。
     * 一旦所有需要更新的数据都已经被更新了，应该调用 digest 方法之一完成哈希计算。
     * 对于给定数量的更新数据，digest 方法只能被调用一次。
     * 在调用 digest 之后，MessageDigest 对象被重新设置成其初始状态。
     */
    public static String encrypByMd5(String context) {
        StringBuffer buf = new StringBuffer("");
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(context.getBytes());//update处理
            byte[] encryContext = md.digest();//调用该方法完成计算
            int i;
            for (int offset = 0; offset < encryContext.length; offset++) {//做相应的转化（十六进制）
                i = encryContext[offset];
                if (i < 0) {
                    i += 256;
                }
                if (i < 16) {
                    buf.append("0");
                }
                buf.append(Integer.toHexString(i));
            }
            System.out.println("32result: " + buf.toString());// 32位的加密
            System.out.println("16result: " + buf.toString().substring(8, 24));// 16位的加密
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return buf.toString();
    }

    /**
     * 判断是否微信浏览器
     */
    public static boolean checkWechat(HttpServletRequest request) {
        boolean flag = true;
        String ua = request.getHeader("user-agent")
                .toLowerCase();
        if (ua.indexOf("micromessenger") <= 0) {// 是微信浏览器
            flag = false;
        }
        return flag;
    }

    /**
     * 删除字符串中指定字符
     *
     * @param str
     * @param delChar
     * @return
     */
    public static String deleteString0(String str, char delChar) {
        String delStr = "";
        for (int i = 0; i < str.length(); i++) {
            if (str.charAt(i) != delChar) {
                delStr += str.charAt(i);
            }
        }
        return delStr;
    }

    //java8list去重
    public static List<String> delRepeat(List<String> list) {
        List<String> myList = list.stream().distinct().collect(Collectors.toList());
        return myList;
    }

    public static String listToString(List<String> list, String chart) {
        String resultString = "";
        if (null == list && list.size() <= 0) {
            System.out.println("list内容为空！");
        } else {
            StringBuilder sb = new StringBuilder();
            boolean flag = false;
            for (String str : list) {
                if (flag) {
                    sb.append(chart);
                } else {
                    flag = true;
                }
                sb.append(str);
            }
            resultString = sb.toString();
        }
        return resultString;
    }

    public static List<String> JsonStringToList(String jsonString) {
        List<String> ids = new ArrayList<>();
        List<Map<String, Object>> jsono = JSON.parseObject(jsonString, List.class);
        for (Map MapVo : jsono) {
            Map<String, Object> Mapbean = JSON.parseObject(JSON.toJSONString(MapVo.get("funcscope_category")), Map.class);
            ids.add(Mapbean.get("id").toString());
        }
        return ids;
    }

    /**
     * BigDecimal类型保留两位小数
     *
     * @return
     */
    public static BigDecimal KeepTwoDecimal(BigDecimal num) {
        DecimalFormat df = new DecimalFormat("#.00");
        return new BigDecimal(df.format(num));
    }

    //系统时间加上指定时间后的时间
    public static Date getTimeForAdd(int day, int hour, int minute, int second) throws Exception {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Calendar nowTime = Calendar.getInstance();
//        nowTime.clear();//1970年1月1日 0点0分0秒
        nowTime.add(Calendar.DATE, day);
        nowTime.add(Calendar.HOUR, hour);
        nowTime.add(Calendar.MINUTE, minute);
        nowTime.add(Calendar.SECOND, second);
        Date date = sdf.parse(sdf.format(nowTime.getTime()));
        return date;
    }

    public static Map<String, Object> removeNullOrEmpty(Map<String, Object> parame) {
        Map<String, Object> result = new HashMap<>();
        for (String key : parame.keySet()) {
            Object value = parame.get(key);
            if (StringUtils.isNotNull(result) && value != "") {
                result.put(key, value);
            }
        }
        return result;
    }


    public static Long[] stringConvertInt(String value) {
        Long[] intArr = new Long[0];
        if (isNull(value)) {
            intArr = new Long[0];
        } else {
            String[] valueArr = value.split(",");
            intArr = new Long[valueArr.length];
            for (int i = 0; i < valueArr.length; i++) {
                intArr[i] = Long.parseLong(valueArr[i]);
            }
        }
        return intArr;
    }

    private static boolean isNull(String param) {
        if (param == null || param.isEmpty() || param.trim().equals("")) {
            return true;
        }
        return false;
    }

    /**
     * 版本号比较
     *
     * @param v1
     * @param v2
     * @return 0代表相等，1代表左边大，-1代表右边大
     * Utils.compareVersion("1.0.358_20180820090554","1.0.358_20180820090553")=1
     */
    public static int compareVersion(String v1, String v2) {
        if (v1.equals(v2)) {
            return 0;
        }
        String[] version1Array = v1.split("[._]");
        String[] version2Array = v2.split("[._]");
        int index = 0;
        int minLen = Math.min(version1Array.length, version2Array.length);
        long diff = 0;

        while (index < minLen
                && (diff = Long.parseLong(version1Array[index])
                - Long.parseLong(version2Array[index])) == 0) {
            index++;
        }
        if (diff == 0) {
            for (int i = index; i < version1Array.length; i++) {
                if (Long.parseLong(version1Array[i]) > 0) {
                    return 1;
                }
            }
            for (int i = index; i < version2Array.length; i++) {
                if (Long.parseLong(version2Array[i]) > 0) {
                    return -1;
                }
            }
            return 0;
        } else {
            return diff > 0 ? 1 : -1;
        }
    }

    public static void write(String path, String fileName, String content) throws IOException {
        File file = new File(path);
        if (!file.exists()) {//如果文件夹不存在
            file.mkdirs();//创建文件夹
        }
        StringBuilder filePath = new StringBuilder();
        filePath = filePath.append(path).append("\\").append(fileName);
        //将写入转化为流的形式
        BufferedWriter bw = new BufferedWriter(new FileWriter(filePath.toString()));
        //一次写一行
        bw.write(content);
        bw.newLine(); //换行用
        //关闭流
        bw.close();
        System.out.println("写入成功");
    }

    /**
     * 获取企业ak编号
     *
     * @return
     */
    public static String setAK() {
        StringBuilder ak = new StringBuilder();
        SimpleDateFormat df = new SimpleDateFormat("yyMMddHH");//设置日期格式
        String date = df.format(DateUtils.getCountryNowTime());//为获取当前系统时间，也可使用当前时间戳
        ak.append(date);
        //四位随机数
        ak.append(CommonUitl.getQrcodeRandom(4));
        return ak.toString();
    }

    /**
     * 通过输入指定日期时间生成cron表达式
     *
     * @param date
     * @return cron表达式
     */
    public static String getCron(Date date) {
        String dateFormat = "ss mm HH dd MM ? yyyy";
        SimpleDateFormat sdf = new SimpleDateFormat(dateFormat);
        String formatTimeStr = null;
        if (date != null) {
            formatTimeStr = sdf.format(date);
        }

        return formatTimeStr;
    }

    public static String getAkByUrl(String URL, String baseDir) {
        String ak = null;
        String[] urlArry = URL.split(baseDir);
        if (StringUtils.isNotNull(urlArry) && urlArry.length > 1) {
            String[] url = urlArry[0].split("/");
            ak = url[url.length - 1];
        }
        return ak;
    }

    public static String getRandomFileName() {
        SimpleDateFormat simpleDateFormat;
        simpleDateFormat = new SimpleDateFormat("yyyyMMdd");
        String str = simpleDateFormat.format(DateUtils.getCountryNowTime());
        Random random = new Random();
        int rannum = (int) (random.nextDouble() * (99999 - 10000 + 1)) + 10000;// 获取5位随机数
        return rannum + str;// 当前时间
    }


    //*******************************以 下 代 码 为 系 统 所 用 到*******************************

    //生成图片库商品编码
    public static String toGetGoodsNo() {
        StringBuilder productNo = new StringBuilder();
        SimpleDateFormat df = new SimpleDateFormat("yyyyMMdd");//设置日期格式
        String date = df.format(DateUtils.getCountryNowTime());// 为获取当前系统时间，也可使用当前时间戳
        productNo.append("GI");
        productNo.append(date);
        productNo.append(CommonUitl.getQrcodeRandom(4));
        return productNo.toString();
    }

    //生成字典值
    public static String toGetDictNo() {
        StringBuilder dictNo = new StringBuilder();
        SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");//设置日期格式
        String date = df.format(DateUtils.getCountryNowTime());// 为获取当前系统时间，也可使用当前时间戳
        dictNo.append("DICT");
        dictNo.append(date);
        dictNo.append(CommonUitl.getQrcodeRandom(6));
        return dictNo.toString();
    }

    //生成会员编码
    public static String toGetMemberNo() {
        StringBuilder memberNo = new StringBuilder();
        SimpleDateFormat df = new SimpleDateFormat("yyMMddHHmm");//设置日期格式
        String date = df.format(DateUtils.getCountryNowTime());// 为获取当前系统时间，也可使用当前时间戳
        memberNo.append("MB");
        memberNo.append(date);
        memberNo.append(CommonUitl.getQrcodeRandom(4));
        return memberNo.toString();
    }

    //生成图片库主订单编号
    public static String getMorderNum() {
        StringBuilder mainNo = new StringBuilder();
        SimpleDateFormat df = new SimpleDateFormat("yyMMddHHmmss");//设置日期格式
        String date = df.format(DateUtils.getCountryNowTime());// 为获取当前系统时间，也可使用当前时间戳
        mainNo.append("MI");
        mainNo.append(date);
        mainNo.append(CommonUitl.getQrcodeRandom(6));
        return mainNo.toString();
    }

    //生成图片库子订单编号
    public static String getOrderNum() {
        StringBuilder orderNo = new StringBuilder();
        SimpleDateFormat df = new SimpleDateFormat("yyMMddHHmmss");//设置日期格式
        String date = df.format(DateUtils.getCountryNowTime());// 为获取当前系统时间，也可使用当前时间戳
        orderNo.append("OI");
        orderNo.append(date);
        orderNo.append(CommonUitl.getQrcodeRandom(6));
        return orderNo.toString();
    }

    //生成mqtt设备ID
    public static String toGetMqttDeviceId() {
        StringBuilder driveNo = new StringBuilder();
        SimpleDateFormat df = new SimpleDateFormat("yyMMddHHmmss");//设置日期格式
        String date = df.format(DateUtils.getCountryNowTime());// 为获取当前系统时间，也可使用当前时间戳
        driveNo.append("D");
        driveNo.append(date);
        driveNo.append(CommonUitl.getQrcodeRandom(6));
        return driveNo.toString();
    }

    //生成存储规则编号
    public static String getStorageRuleNo() {
        StringBuilder storageNo = new StringBuilder();
        SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");//设置日期格式
        String date = df.format(DateUtils.getCountryNowTime());// 为获取当前系统时间，也可使用当前时间戳
        storageNo.append(date);
        return storageNo.toString();
    }

    //图层参数-生成临时文件名
    public static String getFileName() {
        StringBuilder fileName = new StringBuilder();
        SimpleDateFormat df = new SimpleDateFormat("yyMMddHHmmss");//设置日期格式
        String date = df.format(DateUtils.getCountryNowTime());// 为获取当前系统时间，也可使用当前时间戳
        fileName.append("PMBK");
        fileName.append(date);
        fileName.append(CommonUitl.getQrcodeRandom(6));
        return fileName.toString();
    }

}
